package com.scs.application.modules.dept.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.entity.DataEntity;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.flow.FlowContext;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.Supplier;
import com.scs.application.modules.base.entity.Warehouse;
import com.scs.application.modules.base.mapper.MatrMapper;
import com.scs.application.modules.base.mapper.SupplierMapper;
import com.scs.application.modules.base.service.WarehouseService;
import com.scs.application.modules.dept.dto.DemandSumDTO;
import com.scs.application.modules.dept.entity.Demand;
import com.scs.application.modules.dept.entity.DemandItem;
import com.scs.application.modules.dept.entity.DemandSum;
import com.scs.application.modules.dept.entity.DemandSumItem;
import com.scs.application.modules.dept.mapper.DemandItemMapper;
import com.scs.application.modules.dept.mapper.DemandSumItemMapper;
import com.scs.application.modules.dept.mapper.DemandSumMapper;
import com.scs.application.modules.dept.service.DemandItemService;
import com.scs.application.modules.dept.service.DemandService;
import com.scs.application.modules.dept.service.DemandSumService;
import com.scs.application.modules.purchase.entity.Order;
import com.scs.application.modules.purchase.entity.OrderItem;
import com.scs.application.modules.purchase.enums.PoType;
import com.scs.application.modules.purchase.mapper.OrderItemMapper;
import com.scs.application.modules.purchase.mapper.OrderMapper;
import com.scs.application.modules.wm.dto.WorkOrderKey;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Slf4j
@Service
public class DemandSumServiceImpl extends BaseServiceImpl<DemandSumMapper, DemandSum> implements DemandSumService {

    @Autowired
    private DemandSumItemMapper demandSumItemMapper;


    @Autowired
    private DemandItemService demandItemService;

    @Autowired
    private DemandService demandService;
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private MatrMapper matrMapper;

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private SupplierMapper supplierMapper;

    @Autowired
    private WarehouseService warehouseService;
    @Autowired
    private DemandItemMapper demandItemMapper;

    @Override
    public boolean saveOrUpdate(DemandSum entity) {

        if (StringUtils.isBlank(entity.getBusKey())) {
            entity.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.DEPT_DEMAND_SUM_KEY));
        }
        return super.saveOrUpdate(entity);
    }

    @Override
    public boolean removeCascadeByIds(Collection<? extends Serializable> idList) {
        List<DemandSumItem> sumItems = demandSumItemMapper.selectList(Wrappers.<DemandSumItem>query().in("demand_sum_id", idList));

        demandSumItemMapper.delete(Wrappers.<DemandSumItem>query().in("demand_sum_id", idList));

        boolean success = super.removeCascadeByIds(idList);
//        更新回待审核状态
        sumItems.forEach(item ->{
            demandService.update(Wrappers.<Demand>update().set("flow_status", "submit").eq("id", item.getDemandId()));
        });

        return success;
    }

    @Override
    protected void afterHandleFlowChange(FlowContext flowContext, DemandSum newEntity) {
        super.afterHandleFlowChange(flowContext, newEntity);

        String buttonKey = flowContext.getButtonKey();
        if ("pass".equalsIgnoreCase(buttonKey)) {
            DemandSum demandSum = flowContext.getBusEntity();
            List<DemandSumItem> sumItems = demandSumItemMapper.selectList(Wrappers.<DemandSumItem>query().in("demand_sum_id", demandSum.getId()));
            if(sumItems == null || sumItems.size() <1) throw new BusinessException("该需求汇总单没有明细数据，无法审核通过");
            List<String> idList = sumItems.stream().map(item -> item.getDemandId()).collect(Collectors.toList());

            List<Demand> demands = demandService.list(Wrappers.<Demand>query().in("id", idList));
            int count = 0;
            for (Demand demand : demands) {
                List<Order> orders = convertDemandToOrders(demand);
                count += orders.size();
                demandService.update(Wrappers.<Demand>update().set("flow_status", "end").eq("id", demand.getId()));

            }

            flowContext.setHandledMsg(String.format("需求计划审核完成，共生成%d个采购订单", count));
            log.info("需求计划审核完成，共生成{}个采购订单", count);
        }

    }

    /**
     * 将需求转换为采购订单，依据 耗材所属供应商、购销、一物一码 的不同可能产生多张订单
     * 1.购销 一物一码 订单
     * 2.购销 非一物一码 订单
     * 3.代销 非一物一码 订单
     * 4.非代销 非一物一码 订单
     *
     * @param demand
     */
    private List<Order> convertDemandToOrders(Demand demand) {
        String demandId = demand.getId();

        List<DemandItem> demandItems = demandItemMapper.selectList(Wrappers.<DemandItem>query().eq("demand_id", demandId));
        if (demandItems.isEmpty()) {
            throw new BusinessException("需求明细为空，转换采购订单失败");
        }

        List<Matr> matrs = matrMapper.selectBatchIds(demandItems.stream().map(item -> item.getMatrId()).collect(Collectors.toList()));
        if (matrs.isEmpty()) {
            throw new BusinessException("需求明细所对应的耗材在系统中不存在，转换采购订单失败");
        }

        // key为耗材ID，value为耗材对象
        Map<String, Matr> matrMap = matrs.stream().collect(Collectors.toMap(matr -> matr.getId(), matr -> matr));

        // 依据供应商
        Map<WorkOrderKey, List<DemandItem>> groupDemandItem = Maps.newHashMap();

        // 依据耗材购销/代销、一物一码属性进行拆分
        for (DemandItem item : demandItems) {
            String matrId = item.getMatrId();

            Matr matr = matrMap.get(matrId);
            if (matr == null) {
                // 明细中的耗材 在 耗材表中 不存在
                throw new BusinessException("品名：%s，品规：%s 在耗材基础数据中不存在，转换采购订单失败",
                        item.getMatrName(), item.getMatrSpec());
            }
            Boolean flagConsignment = matr.getFlagConsignment();
            Boolean flagOmoc = matr.getFlagOmoc();

            WorkOrderKey orderKey = new WorkOrderKey(matr.getSupplierId(), matr.getSupplierName(), flagConsignment, flagOmoc);
            List<DemandItem> items = groupDemandItem.get(orderKey);
            if (items == null) {
                items = Lists.newArrayList();
            }
            items.add(item);
            groupDemandItem.put(orderKey, items);

        }

        Warehouse warehouse =  warehouseService.getApplyWarehouseByWarehouseId(demand.getApplyWarehouseId());;
        if(warehouse == null) {
            throw new BusinessException("未配置中心库房，转换采购订单失败");
        }
        ArrayList<Order> orders = Lists.newArrayList();
        for (WorkOrderKey orderKey : groupDemandItem.keySet()) {
            Order order = convertDemandItemsToOrder(orderKey, demand, groupDemandItem.get(orderKey), warehouse);
            orders.add(order);
        }
        return orders;
    }

    private Order convertDemandItemsToOrder(WorkOrderKey orderKey,
                                            Demand demand, List<DemandItem> demandItems, Warehouse warehouse) {

        String supplierId = orderKey.supplierId;
        Supplier supplier = supplierMapper.selectById(supplierId);
        if (supplier == null) {
            log.error("转换采购订单失败，需求单号：{}，供应商 {} 不存在", demand.getBusKey(), supplierId);
            throw new BusinessException("转换采购订单失败");
        }

        // 订单金额求和
        double sum = demandItems.stream().mapToDouble(o -> o.getAmount()).sum();

        String orderCode = serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.PURCHASE_ORDER_KEY);
        Order order = new Order();
        order.setBusKey(orderCode)
                .setSupplierId(supplierId)
                .setSupplierName(supplier.getName())
                .setBusDate(new Date())
                .setBusUser(demand.getBusUser())
                .setDeptId(demand.getDeptIdTarget())
                .setDeptName(demand.getDeptNameTarget())
                .setDeptIdDemand(demand.getDeptId())
                .setDeptNameDemand(demand.getDeptName())
                .setFlagOmoc(orderKey.getFlagOmoc())
                .setPoType(orderKey.getFlagConsignment() ? PoType.CONSIGNMENT.getValue() : PoType.BUY.getValue())
                .setDateLates(DateUtils.addDays(new Date(), 3))
                .setAmount(sum)
                .setFlagPushed(false)
                .setWarehouseId(warehouse.getId())
                .setWarehouseName(warehouse.getName())
                .setRefTable("dept_demand")
                .setRefId(demand.getId())
                .setRefKey(demand.getBusKey())
                .setRemark(String.format("由需求计划 %s 转换而来", demand.getBusKey()));
        ;
        orderMapper.insert(order);

        for (DemandItem demandItem : demandItems) {
            OrderItem orderItem = new OrderItem();
            String[] ignoreFields = Arrays.asList(DataEntity.class.getDeclaredFields())
                    .stream().map(field -> field.getName()).collect(Collectors.toList()).toArray(new String[]{});
            BeanUtils.copyProperties(demandItem, orderItem, ignoreFields);
            orderItem.setOrderId(order.getId())
                    .setRefId(demandItem.getId())
                    .setRemark(String.format("由需求计划 %s 转换而来", demand.getBusKey()));
            orderItemMapper.insert(orderItem);
        }

        // 回写需求计划明细 采购订单ID 字段
        List<String> demandIds = demandItems.stream().map(o -> o.getId()).collect(Collectors.toList());
        demandItemMapper.update(null, Wrappers.<DemandItem>update().set("order_id", order.getId()).in("id", demandIds));

        return order;
    }
    @Override
    public boolean addByDemand(DemandSumDTO demandSumDTO) {
        List<Demand> SumDTOS = demandSumDTO.getDemandSumDTOS();
        String demandSunId = demandSumDTO.getDemandSunId();
        SumDTOS.forEach(item ->{
            DemandSumItem sumItem = new DemandSumItem();
            sumItem.setDemandId(item.getId())
                    .setDemandSumId(demandSunId);
            demandSumItemMapper.insert(sumItem);
        });
        List<DemandSumItem> demandSumItems = demandSumItemMapper.selectList(Wrappers.<DemandSumItem>query().select("demand_id").eq("demand_sum_id", demandSunId));
        // 修改订单总金额
        Set<String> idList = demandSumItems.stream().map(item -> item.getDemandId()).collect(Collectors.toSet());
        Double sumAmount = updateDemandSumAmount(idList);
        DemandSum demandSum = new DemandSum();
        demandSum.setAmount(sumAmount).setId(demandSunId);

        demandService.update(Wrappers.<Demand>update().set("flow_status", "collect").in("id", idList));
        return super.updateCascadeById(demandSum);
    }

    private Double updateDemandSumAmount(Set<String> idList) {

        List<DemandItem> demandItems = demandItemService.list(Wrappers.<DemandItem>query().select("amount").in("demand_id", idList));
        return demandItems.stream().mapToDouble(o -> o.getAmount()).sum();
    }


    @Override
    public List<DemandSum> ListWithItem(QueryWrapper wrapper) {
        return baseMapper.listWithItem(wrapper);
    }
}
